package cn.htsyb.synergy.maker.engine.impl;

import cn.htsyb.synergy.maker.config.Maker;
import cn.htsyb.synergy.maker.config.meta.Database;
import cn.htsyb.synergy.maker.engine.IDBMetaEngine;
import cn.htsyb.synergy.maker.model.*;
import cn.htsyb.synergy.maker.util.ResultSetUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class MysqlMetaEngine implements IDBMetaEngine {
    private final static Logger logger = LoggerFactory.getLogger(MysqlMetaEngine.class);
    Maker maker;
    Database database;
    private Connection dsConnection;

    public MysqlMetaEngine(Maker config) {
        initEngine(config);
    }

    @Override
    public void initEngine(Maker config) {
        this.maker = config;
        this.database = maker.getDatabase();

    }
    @Override
    public List<MetaTable> generate() throws SQLException {
        return this.getDBMeta();
    }

    public Connection createDBConnection() throws SQLException {
        if (dsConnection == null) {
            //URL中一定要增加参数"remarks=true&useInformationSchema=true"
            dsConnection = DriverManager.getConnection(
                    database.getDriverUrl(),
                    database.getUsername(),
                    database.getPassword()
            );


        }
        return dsConnection;
    }

    public void closeDBConnection() throws SQLException {
        if (dsConnection != null) {
            dsConnection.close();
            dsConnection = null;
        }
    }

    /**
     * 获取表meta信息
     *
     * @return
     * @throws SQLException
     */
    public List<MetaTable> getDBMeta() throws SQLException {
        List<MetaTable> tableList = new ArrayList<MetaTable>();
        DatabaseMetaData meta = createDBConnection().getMetaData();
        try {

            String[] makerTablePattern = maker.getCompile().getMakerTablePattern();
            for (String tablePattern : makerTablePattern) {
                tableList.addAll(getMetaTable(meta, tablePattern));
            }

            for (MetaTable metaTable : tableList) {
                getMetaColumn(meta, metaTable);
            }
        } catch (Exception ex) {
            logger.warn("", ex);
        } finally {
            closeDBConnection();
        }

        return tableList;
    }

    /**
     * 获取表的元数据信息
     *
     * @param meta
     * @param tableName
     * @return
     */
    private List<MetaTable> getMetaTable(DatabaseMetaData meta, String tableName) throws Exception {
        List<MetaTable> tableList = new ArrayList<>();
        ResultSet tableRs = meta.getTables(database.getCatalog(), database.getSchema(), tableName, new String[]{"TABLE", "VIEW"});

        while (tableRs.next()) {
            tableList.add(ResultSetUtil.metaToBean(tableRs, MetaTable.class));
        }
        return tableList;
    }

    /**
     * 获取列的元数据信息
     *
     * @param dbMetaData
     * @param metaTable
     * @return
     */
    private void getMetaColumn(DatabaseMetaData dbMetaData, MetaTable metaTable) throws Exception {
        //提取索引
        ResultSet indexRS = dbMetaData.getIndexInfo(database.getCatalog(), database.getSchema(), metaTable.getTableName(), false, true);
        while (indexRS.next()) {
            metaTable.getIndexs().add(ResultSetUtil.metaToBean(indexRS, MetaIndex.class));
        }
        //提取主键
        ResultSet filedPkRS = dbMetaData.getPrimaryKeys(database.getCatalog(), database.getSchema(), metaTable.getTableName());
        while (filedPkRS.next()) {
            metaTable.getPkColumns().add(ResultSetUtil.metaToBean(filedPkRS, MetaPKColumn.class));
        }
        //提取外键
        ResultSet filedFkRS = dbMetaData.getExportedKeys(database.getCatalog(), database.getSchema(), metaTable.getTableName());
        while (filedFkRS.next()) {
            metaTable.getFkColumns().add(ResultSetUtil.metaToBean(filedFkRS, MetaFKColumn.class));
        }
        //提取所有字段
        ResultSet filedRS = dbMetaData.getColumns(database.getCatalog(), database.getSchema(), metaTable.getTableName(), "%");
        while (filedRS.next()) {
            MetaColumn metaColumn = ResultSetUtil.metaToBean(filedRS, MetaColumn.class);
            //标明metaColumn中字段是否为主键
            for (MetaPKColumn pkColumn:metaTable.getPkColumns()) {
                if (pkColumn.getColumnName().equals(metaColumn.getColumnName())) {
                    metaColumn.setHasPrimaryKey(true);
                }
            }
            metaTable.getColumns().add(metaColumn);
        }
    }
}
